Function.RegisterNamespace("System.IO.FileStrategy.SpiderMonkey");

System.IO.FileStrategy.SpiderMonkey.Posix=function(){
    // Private Members
    var _bufferSize=100000;
    var _unicodeRegex=/[^\u0000-\u00ff]/;

    // IFileStrategy Members
    this.DeleteFile=function(path){
        if(this.Exists(path)){
            return system(String.Format("rm -f '{0}'",escapePath(path)));
        }
        return false;
    };
    
    this.Exists=function(path){
        return System.Environment.Execute("sh", ["-c",String.Format("\"test -f '{0}' && echo 1 || echo 0\"",escapePath(path))])==1;
    };

    this.GetFile=function(path){
        if(this.Exists(path)){
            return read(path);
        }
        return null;
    };
        
    this.SaveFile=function(path,text){
        this.DeleteFile(path);
        if(text==undefined||!text.length){
            return System.Environment.Execute("touch",[String.Format("'{0}'",escapePath(path))],true);
        }
        var chunks=Math.ceil(text.length/_bufferSize);
        for(var i=0;i<chunks;i++){
            var index=i*_bufferSize;
            var chunk=text.slice(index,index+_bufferSize);
            if(_unicodeRegex.test(chunk)){
                System.Environment.Execute("sh", ["-c",String.Format("\"printf '\\{1}'\" >> '{0}'",escapePath(path),convertToUtf8(chunk).join("\\"))],true);
            }else{
                System.Environment.Execute("sh", ["-c",String.Format("cat >> '{0}' << '_EOF_'\n{1}\n_EOF_",escapePath(path),chunk)],true);
                System.Environment.Execute("perl", ["-pi","-e","'chomp if eof'",String.Format("'{0}'",escapePath(path))],true);
            }
        }
    };

    // IStrategySpecification Members
    this.IsSatisfiedBy=function(candidate){
        if(typeof(system)!='undefined' && typeof(version)!='undefined' && typeof(snarf)!="undefined"){
            try{
                var exitCode=system("uname > NUL 2>&1");
                if(exitCode==0){
                    system("rm -f NUL");
                    return true;
                }
            }catch(e){}
        }
        return false;
    };

    // Private Methods
    function convertToUtf8(text){
        var output=[];
        for(var i=0;i<text.length;i++){
            var char=text.charCodeAt(i);
            if(char<0x80)output.push(char.toString(8));
            else if(char<0x800){
                output.push((0xC0|(char>>6)).toString(8));
                output.push((0x80|(char&0x3F)).toString(8));
            }else if(char<0xD800||char>=0xE000){
                output.push((0xE0|(char>>12)).toString(8));
                output.push((0x80|((char>>6)&0x3F)).toString(8));
                output.push((0x80|(char&0x3F)).toString(8));
            }else{
                char=((char&0x3FF)<<10)|(text.charCodeAt(++i)&0x3FF)+0x10000;
                output.push((0xF0|(char>>18)).toString(8));
                output.push((0x80|((char>>12)&0x3F)).toString(8));
                output.push((0x80|((char>>6)&0x3F)).toString(8));
                output.push((0x80|(char&0x3F)).toString(8));
            }
        }
        return output;
    }

    function escapePath(path){
        return (path||'').replace(/'/g,"'\\''");
    }
};

System.IO.FileStrategy.SpiderMonkey.Posix.Implement(System.IO.FileStrategy.IFileStrategy,'System.IO.FileStrategy.SpiderMonkey.Posix');
System.IO.FileStrategy.SpiderMonkey.Posix.Implement(System.Script.Strategy.IStrategySpecification,'System.IO.FileStrategy.SpiderMonkey.Posix');

System.IO.File.Strategies.Add(System.IO.FileStrategy.SpiderMonkey.Posix);